package com.softserveinc.ita.kaiji.service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.softserveinc.ita.kaiji.model.game.*;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.softserveinc.ita.kaiji.dto.GameInfoDto;
import com.softserveinc.ita.kaiji.model.player.bot.Bot;
import com.softserveinc.ita.kaiji.model.player.bot.BotFactory;
import com.softserveinc.ita.kaiji.model.Card;
import com.softserveinc.ita.kaiji.model.player.HumanPlayer;
import com.softserveinc.ita.kaiji.model.player.Player;

/**
 * 
 * @author Bohdan Shaposhnik
 * @version 2.5
 * @since 17.03.2014
 */
@Service
public class GameServiceImpl implements GameService {

	private static Logger logger = Logger.getLogger(GameServiceImpl.class);

	private static final List<Game> GAMES = new ArrayList<Game>();
	private static final List<Player> PLAYERS = new ArrayList<Player>();

	@Autowired
	private GameFactory gameFactory;

	private GameInfo setGameInfo(GameInfoDto gameInfoDto) {

		if (logger.isTraceEnabled()) {
			logger.trace("setGameInfo: we are in");
		}
		Set<Player> playersSet = new HashSet<Player>();
		playersSet.add(new HumanPlayer(gameInfoDto.getPlayerName(), gameInfoDto
				.getNumberOfCards()));

		if (gameInfoDto.isBotGame()) {
			Bot bot = BotFactory.createBot(gameInfoDto.getBotType(),
					gameInfoDto.getNumberOfCards());
			playersSet.add(bot);
			if (logger.isTraceEnabled()) {
				logger.trace("setGameInfo: bot added to the set of players");
			}
		}
		GameInfo newGameInfo = new GameInfoImpl(gameInfoDto.getGameName(),
				gameInfoDto.getPlayerName(), gameInfoDto.getNumberOfCards(),
				gameInfoDto.isBotGame(), gameInfoDto.getBotType(), playersSet);
		return newGameInfo;
	}

	@Override
	public void finishGame(Integer gameId) throws IllegalArgumentException{
		if (logger.isTraceEnabled()) {
			logger.trace("finishGame: started");
		}
		Game game = getGameById(gameId);
		game.finishGame();
		GAMES.remove(gameId);
		Integer playerId = getPlayerIdFromGame(gameId);
		PLAYERS.remove(playerId);
	}

	@Override
	public GameInfo getGameInfo(Integer gameId) throws IllegalArgumentException {
		return getGameById(gameId).getGameInfo();
	}

	@Override
	public Integer createGame(GameInfoDto gameInfoDto) {
		GameInfo gameInfo = setGameInfo(gameInfoDto);
		Game game = gameFactory.makeGame(gameInfo);
		if (GAMES.contains(game)) {
			if (logger.isTraceEnabled()) {
				logger.trace("createGame: game is already in pool");
			}
			return game.getId();
		}
		GAMES.add(game);
		game.setId(GAMES.indexOf(game));
		if (logger.isTraceEnabled()) {
			logger.trace("createGame: game added");
		}
		addPlayers(game);
		return game.getId();
	}

	@Override
	public void makeTurn(Integer gameId, Integer playerId, Card card)
			throws IllegalArgumentException {
		Player activePlayer = null;
		for (Player player : PLAYERS) {
			if (player.getId() == playerId)
				activePlayer = player;
		}
		Game game = getGameById(gameId);
			for (Player player : game.getGameInfo().getPlayers()) {
				if (player.isBot()) {
					Bot bot = (Bot) player;
					bot.setGameData(game.getGameHistory());
				}
			}
			if (logger.isTraceEnabled()) {
				logger.trace("makeTurn: exucuting a turn");
			}
			game.makeTurn(card, activePlayer);

	}

	@Override
	public Game.State getGameStatus(Integer gameId)
			throws IllegalArgumentException {
		return getGameById(gameId).getState();
	}

	@Override
	public GameHistory getGameHistory(Integer gameId)
			throws IllegalArgumentException {
		return getGameById(gameId).getGameHistory();
	}

	// TODO: It's moving to PlayerService
	@Override
	public Player getPlayerById(Integer playerId) {
		for (Player player : PLAYERS) {
			if (player.getId().equals(playerId))
				return player;
		}
		return null;
	}

	@Override
	public Integer getPlayerIdFromGame(Integer gameId)
			throws IllegalArgumentException {
		Game game = getGameById(gameId);
		for (Player player : game.getGameInfo().getPlayers()) {
			if (!player.isBot()) {
				return player.getId();
			}
		}
		return null;
	}

	private Game getGameById(Integer gameId) throws IllegalArgumentException {
		for (Game game : GAMES) {
			if (game.getId().equals(gameId)) {
				if (logger.isTraceEnabled()) {
					logger.trace("findGameById: game found");
				}
				return game;
			}
			if (logger.isTraceEnabled()) {
				logger.trace("findGameById: game not found");
			}
		}
		throw new IllegalArgumentException(
				"There is no game with such id started!");
	}

	private void addPlayers(Game game) {
		GameInfo gameInfo = game.getGameInfo();
		for (Player player : gameInfo.getPlayers()) {
			if (!player.isBot()) {
				PLAYERS.add(player);
				player.setId(PLAYERS.indexOf(player));
				if (logger.isTraceEnabled()) {
					logger.trace("player added to pool");
				}
			}
		}
	}

}
